package handler

import (
	"SmartLibrary/api/v1"
	"SmartLibrary/internal/service"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"github.com/juju/ratelimit"
	"go.uber.org/zap"
	"net/http"
	"strconv"
	"time"
)

var connectionLimiter = ratelimit.NewBucket(time.Second, 10) // 每秒允许十个连接
type UserHandler struct {
	*Handler
	userService service.UserService
}

func NewUserHandler(handler *Handler, userService service.UserService) *UserHandler {
	return &UserHandler{
		Handler:     handler,
		userService: userService,
	}
}

// Login 登录
// @Summary 账号登录
// @Schemes
// @Description
// @Tags 用户模块
// @Accept json
// @Produce json
// @Param request body v1.LoginRequest true "params"
// @Success 200 {object} v1.LoginResponse
// @Router /user/login [post]
func (h *UserHandler) Login(ctx *gin.Context) {
	// 请求参数
	var req v1.LoginRequest
	if err := ctx.ShouldBindJSON(&req); err != nil {
		v1.HandleError(ctx, http.StatusBadRequest, v1.ErrParameterValidation, nil)
		return
	}

	token, err := h.userService.Login(ctx, &req)
	if err != nil {
		v1.HandleError(ctx, http.StatusUnauthorized, err, nil)
		return
	}
	v1.HandleSuccess(ctx, v1.LoginResponseData{
		AccessToken: token,
	})
}

// GetProfile 获取用户信息
// @Summary 获取用户信息
// @Schemes
// @Description
// @Tags 用户模块
// @Accept json
// @Produce json
// @Security Bearer
// @Success 200 {object} v1.GetProfileResponse
// @Router /user [get]
func (h *UserHandler) GetProfile(ctx *gin.Context) {
	// 从上下文中获取用户ID
	userId := GetUserIdFromCtx(ctx)
	if userId == 0 {
		v1.HandleError(ctx, http.StatusUnauthorized, v1.ErrUnauthorized, nil)
		return
	}

	// 根据 UserId 获取用户信息
	user, err := h.userService.GetProfile(ctx, userId)
	if err != nil {
		v1.HandleError(ctx, http.StatusBadRequest, err, nil)
		return
	}

	v1.HandleSuccess(ctx, user)
}

// GetBooks 获取图书信息
// @Summary 获取图书信息
// @Schemes
// @Description 根据条件获取图书信息
// @Tags 用户模块
// @Accept json
// @Produce json
// @Success 200 {object} v1.GetBooksResponse
// @Router /user/books [get]
func (h *UserHandler) GetBooks(ctx *gin.Context) {
	// 获取携带参数
	params := ctx.Request.URL.Query()
	// 获取并校验各属性
	pageNum, err := strconv.Atoi(params.Get("pageNum"))
	if err != nil || pageNum <= 0 {
		v1.HandleError(ctx, http.StatusBadRequest, v1.ErrParameterValidation, nil)
		return
	}
	pageSize, err := strconv.Atoi(params.Get("pageSize"))
	if err != nil || pageSize <= 0 {
		v1.HandleError(ctx, http.StatusBadRequest, v1.ErrParameterValidation, nil)
		return
	}

	req := v1.GetBooksCondition{
		Offset:    (pageNum - 1) * pageSize,
		Limit:     pageSize,
		Condition: params.Get("condition"),
		Query:     params.Get("query"),
	}

	// 判断 Query 字段是否合法
	if req.Query != "" {
		if _, exists := v1.BookValidAttributes[req.Query]; !exists {
			v1.HandleError(ctx, http.StatusBadRequest, v1.ErrParameterValidation, nil)
			return
		}
	}

	books, err := h.userService.GetBooks(ctx, &req)
	if err != nil {
		v1.HandleError(ctx, http.StatusBadRequest, err, nil)
		return
	}
	v1.HandleSuccess(ctx, books)
}

// GetRules 获取规则信息
// @Summary 获取规则信息
// @Schemes
// @Description
// @Tags 用户模块
// @Produce json
// @Param request body model.Rule true "params"
// @Success 200 {object} v1.Response
// @Router /user/rules [get]
func (h *UserHandler) GetRules(ctx *gin.Context) {
	rules, err := h.userService.GetRules(ctx)
	if err != nil {
		v1.HandleError(ctx, http.StatusBadRequest, err, nil)
		return
	}

	v1.HandleSuccess(ctx, rules)
}

// GetNotices 获取公告信息
// @Summary 获取公告信息
// @Schemes
// @Description
// @Tags 用户模块
// @Produce json
// @Param request body model.Notice true "params"
// @Success 200 {object} v1.Response
// @Router /user/notices [get]
func (h *UserHandler) GetNotices(ctx *gin.Context) {
	notices, err := h.userService.GetNotices(ctx)
	if err != nil {
		v1.HandleError(ctx, http.StatusBadRequest, err, nil)
		return
	}

	v1.HandleSuccess(ctx, notices)
}

func (h *UserHandler) GetBorrows(ctx *gin.Context) {
	// 从上下文中获取用户ID
	userId := GetUserIdFromCtx(ctx)
	if userId == 0 {
		v1.HandleError(ctx, http.StatusUnauthorized, v1.ErrUnauthorized, nil)
		return
	}

	// 获取携带参数
	params := ctx.Request.URL.Query()
	// 获取并校验各属性
	pageNum, err := strconv.Atoi(params.Get("pageNum"))
	if err != nil || pageNum <= 0 {
		v1.HandleError(ctx, http.StatusBadRequest, v1.ErrParameterValidation, nil)
		return
	}
	pageSize, err := strconv.Atoi(params.Get("pageSize"))
	if err != nil || pageSize <= 0 {
		v1.HandleError(ctx, http.StatusBadRequest, v1.ErrParameterValidation, nil)
		return
	}

	req := v1.GetBorAndVioCondition{
		UserId:    userId,
		Offset:    (pageNum - 1) * pageSize,
		Limit:     pageSize,
		Condition: params.Get("condition"),
		Query:     params.Get("query"),
	}

	// 判断 Query 字段是否合法
	if req.Query != "" {
		if _, exists := v1.BorrowValidAttributes[req.Query]; !exists {
			v1.HandleError(ctx, http.StatusBadRequest, v1.ErrParameterValidation, nil)
			return
		}
	}

	// 根据借阅条件获取借阅信息
	borrows, err := h.userService.GetBorrows(ctx, &req)
	if err != nil {
		v1.HandleError(ctx, http.StatusBadRequest, err, nil)
		return
	}

	v1.HandleSuccess(ctx, borrows)
}

func (h *UserHandler) GetViolations(ctx *gin.Context) {
	// 从上下文中获取用户ID
	userId := GetUserIdFromCtx(ctx)
	if userId == 0 {
		v1.HandleError(ctx, http.StatusUnauthorized, v1.ErrUnauthorized, nil)
		return
	}

	// 获取携带参数
	params := ctx.Request.URL.Query()
	// 获取并校验各属性
	pageNum, err := strconv.Atoi(params.Get("pageNum"))
	if err != nil || pageNum <= 0 {
		v1.HandleError(ctx, http.StatusBadRequest, v1.ErrParameterValidation, nil)
		return
	}
	pageSize, err := strconv.Atoi(params.Get("pageSize"))
	if err != nil || pageSize <= 0 {
		v1.HandleError(ctx, http.StatusBadRequest, v1.ErrParameterValidation, nil)
		return
	}

	req := v1.GetBorAndVioCondition{
		UserId:    userId,
		Offset:    (pageNum - 1) * pageSize,
		Limit:     pageSize,
		Condition: params.Get("condition"),
		Query:     params.Get("query"),
	}

	// 判断Query字段是否合法
	if req.Query != "" {
		if _, exists := v1.ViolationValidAttributes[req.Query]; !exists {
			v1.HandleError(ctx, http.StatusBadRequest, v1.ErrParameterValidation, nil)
			return
		}
	}

	violations, err := h.userService.GetViolations(ctx, &req)
	if err != nil {
		v1.HandleError(ctx, http.StatusBadRequest, err, nil)
		return
	}
	v1.HandleSuccess(ctx, violations)
}

func (h *UserHandler) GetComments(ctx *gin.Context) {
	comments, err := h.userService.GetComments(ctx)
	if err != nil {
		v1.HandleError(ctx, http.StatusBadRequest, err, nil)
		return
	}
	v1.HandleSuccess(ctx, comments)
}

func (h *UserHandler) CreateComment(ctx *gin.Context) {
	// 从上下文中获取用户ID
	userId := GetUserIdFromCtx(ctx)
	if userId == 0 {
		v1.HandleError(ctx, http.StatusUnauthorized, v1.ErrUnauthorized, nil)
		return
	}

	var req v1.CreateCommentRequest
	if err := ctx.ShouldBindJSON(&req); err != nil {
		v1.HandleError(ctx, http.StatusBadRequest, v1.ErrBadRequest, nil)
		return
	}

	req.UserId = userId

	if err := h.userService.CreateComment(ctx, &req); err != nil {
		v1.HandleError(ctx, http.StatusBadRequest, err, nil)
		return
	}
	v1.HandleSuccess(ctx, nil)
}

func (h *UserHandler) GetChats(ctx *gin.Context) {
	// 从上下文中获取用户ID
	userId := GetUserIdFromCtx(ctx)

	// 令牌桶限流 桶中没有令牌时拒绝请求
	if connectionLimiter.TakeAvailable(1) < 1 {
		h.logger.Error("too many connections", zap.Int64("userID", userId))
		return
	}

	wsUpdate := websocket.Upgrader{
		CheckOrigin: func(r *http.Request) bool {
			// Todo: 通过 Origin 头验证来源并限制

			if userId == 0 {
				return false
			}

			return true
		},
		HandshakeTimeout: time.Second * 10,
		ReadBufferSize:   1024,
		WriteBufferSize:  1024,
	}

	// 升级请求为 websocket
	ws, err := wsUpdate.Upgrade(ctx.Writer, ctx.Request, nil)
	if err != nil {
		h.logger.Error("bad handshake: ", zap.Error(err))
		return
	}

	defer func(ws *websocket.Conn) {
		err := ws.Close()
		if err != nil {
			h.logger.Error("failed to close websocket connection: ", zap.Error(err))
		}
	}(ws) // 确保在函数结束时关闭连接

	// 处理 websocket 消息
	for {
		var data v1.ChatParams
		err := ws.ReadJSON(&data)
		if err != nil {
			_ = ws.WriteMessage(websocket.CloseMessage, []byte("Read message error, closing..."))
			return
		}

		// 处理消息
		err = h.userService.GetChats(&data, ws)
		if err != nil {
			_ = ws.WriteMessage(websocket.CloseMessage, []byte("Internal server error, closing..."))
			return
		}
	}
}
